package jflowmap.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import jflowmap.FlowMapAttrSpec;
import jflowmap.FlowMapGraph;
import prefuse.data.Edge;
import prefuse.data.Node;

public class Comment {
	
	private final String text;
	private final String title;
	
	private Comment (String title, String text) {
		this.title = title;
		if (isFile(text)) {
			this.text = loadCommentFromFile(text);
		} else {
			this.text = text;
		}
	}

	private String loadCommentFromFile(String filename) {
		final String f = filename.substring(5);
		System.out.println("Loading comment from file: " + f);
		
		File file = new File(f);
		if (file.exists() && file.isFile()) {
			try {
				StringBuffer fileData = new StringBuffer(1000);
			    BufferedReader reader = new BufferedReader(new FileReader(file));
			    char[] buf = new char[1024];
			    int numRead=0;
			    while((numRead=reader.read(buf)) != -1){
			    	String readData = String.valueOf(buf, 0, numRead);
			    	fileData.append(readData);
			    	buf = new char[1024];
			    }
			    reader.close();
			    return fileData.toString();

			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		return "No comment file found at path " + f;
	}

	private boolean isFile(String filename) {
		return filename.startsWith("file:");
	}

	public static List<Comment> on(Node node, FlowMapAttrSpec attrSpec) {
		List<Comment> rv = new Vector<Comment>();
		
		if (node.canGet(attrSpec.getNodeCommentAttr(), String.class))  {
			String comment = node.getString(attrSpec.getNodeCommentAttr());
		
			if (comment != null) {
				rv.add(new Comment(node.getString(attrSpec.getNodeLabelAttr()),
						comment));
			}
		}
		
		for (String attr: attrSpec.getFlowWeightAttrs()) {
			System.out.println("Checking for comment at " + attr + ":" + attrSpec.getNodeCommentAttr()
					+ " for " + FlowMapGraph.getIdOfNode(node));
			
			if (node.canGet(attr + ":" + attrSpec.getNodeCommentAttr(), String.class)) {
				
				String title = node.getString(attr + ": " + attrSpec.getNodeLabelAttr());
				String text = node.getString(attr + ":" + attrSpec.getNodeCommentAttr());
				
				if (text != null)
					rv.add(new Comment(title, text));
			}
		}
		return rv;
	}

	public static List<Comment> on(Edge edge, FlowMapAttrSpec attrSpec) {
		List<Comment> rv = new Vector<Comment>();
		
		if (edge.canGetString(attrSpec.getFlowCommentAttr())) {
			String comment = edge.getString(attrSpec.getFlowCommentAttr());
			if (comment != null) {				
				rv.add(new Comment(edge.getSourceNode().getString(attrSpec.getNodeLabelAttr())
								   + " / " + edge.getTargetNode().getString(attrSpec.getNodeLabelAttr()),
						   		   comment));
			}
		}
		
		for (String attr: attrSpec.getFlowWeightAttrs()) {
			if (edge.canGetString(attrSpec.getFlowCommentAttr(attr))) {
				String comment = edge.getString(attrSpec.getFlowCommentAttr(attr));
				if (comment != null) {					
					rv.add(new Comment(attr + ": " + edge.getSourceNode().getString(attrSpec.getNodeLabelAttr())
									   + " / " + edge.getTargetNode().getString(attrSpec.getNodeLabelAttr()),
									   comment));
				}
			}
		}
		
		return rv;
	}
	
	public static List<Comment> on(Edge edge, String attr, FlowMapAttrSpec attrSpec) {
		List<Comment> rv = new Vector<Comment>();
		
		if (edge.canGetString(attrSpec.getFlowCommentAttr())) {
			String comment = edge.getString(attrSpec.getFlowCommentAttr());
			if (comment != null) {
				rv.add(new Comment(edge.getSourceNode().getString(attrSpec.getNodeLabelAttr())
								   + " / " + edge.getTargetNode().getString(attrSpec.getNodeLabelAttr()),
						   		   comment));
			}
		}
		
		for (String weightAttr: attrSpec.getFlowWeightAttrs()) {
			if (weightAttr.equals(attr)) {
				if (edge.canGetString(attrSpec.getFlowCommentAttr(attr))) {
					String comment = edge.getString(attrSpec.getFlowCommentAttr(attr));
					if (comment != null)
						rv.add(new Comment(attr + ": " + edge.getSourceNode().getString(attrSpec.getNodeLabelAttr())
											+ " / " + edge.getTargetNode().getString(attrSpec.getNodeLabelAttr()),
										   edge.getString(attrSpec.getFlowCommentAttr(attr))));
				}
			}
		}
		
		return rv;
	}
	
	public static List<Comment> allOn (Node node, FlowMapAttrSpec attrSpec) {
		List<Comment> comments = new Vector<Comment>();
		
		comments.addAll(Comment.on(node, attrSpec));
		
		for (Iterator<Edge> iter = node.edges(); iter.hasNext();) {
			Edge edge = iter.next();
			Node target = edge.getSourceNode() == node ? edge.getTargetNode() : edge.getSourceNode();
			comments.addAll(Comment.on(target, attrSpec));
		}
		
		for (Iterator<Edge> iter = node.edges(); iter.hasNext();) {
			Edge edge = iter.next();
			comments.addAll(Comment.on(edge, attrSpec));
		}
		
		return comments;
	}
	
	public static List<Comment> allOn (Node node, String weightAttr, FlowMapAttrSpec attrSpec) {
		List<Comment> comments = new Vector<Comment>();

		comments.addAll(Comment.on(node, attrSpec));
		
		for (Iterator<Edge> iter = node.edges(); iter.hasNext();) {
			Edge edge = iter.next();
			Node target = edge.getSourceNode() == node ? edge.getTargetNode() : edge.getSourceNode();
			comments.addAll(Comment.on(target, attrSpec));
		}
		
		for (Iterator<Edge> iter = node.edges(); iter.hasNext();) {
			Edge edge = iter.next();
			comments.addAll(Comment.on(edge, weightAttr, attrSpec));
		}
		
		return comments;
	}

	
	public String getTitle() {
		return title;
	}
	
	public String getText() {
		return text;
	}

}
